package com.example.smartall.api;

import android.content.Context;
import android.content.Intent;
import android.os.Looper;
import android.util.Log;
import android.widget.Toast;

import androidx.annotation.NonNull;

import com.example.smartall.ui.LoginActivity;
import com.example.smartall.utils.Constant;
import com.example.smartall.utils.MApplication;
import com.example.smartall.utils.SPUtils;

import org.json.JSONObject;

import java.io.IOException;
import java.util.HashMap;
import java.util.Iterator;

import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.MediaType;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;

 /**
  * @Author:         abbas
  * @CreateDate:     2022/2/7
  * @Description:    这里有一窝OkHttp
  */
public class Api {
    private static OkHttpClient client;
    private static String requestUrl;
    private static HashMap<String,Object> params;
    public static Api api = new Api();

    public static Api config(String requestUrl,HashMap<String,Object> params){
        client = new OkHttpClient.Builder()
                .build();
        api.requestUrl = requestUrl;
        api.params = params;
        return api;
    }

    /**
     * POST 请求
     * @param callBack 回调
     * @param token token
     * body参数由config()静态方法传入一个map
     */
    public void postRequest(NetCallBack callBack,String token){
        Log.e("token",token);
        JSONObject jsonObject = new JSONObject(params);
        String jsonStr = jsonObject.toString();
        RequestBody body = RequestBody.create(MediaType.parse("application/json;charset=utf-8"),jsonStr);
        Log.e("TAG",ApiConfig.BASE_URL + requestUrl);
        Request request = new Request.Builder()
                .url(ApiConfig.BASE_URL + requestUrl)
                .addHeader("contentType","application/json;charset=UTF-8")
                .addHeader(Constant.POST_TOKEN,token)
                .post(body)
                .build();
        doCallBack(request,callBack);
    }

    /**
     * PUT 方法 一般需要一个token以及put参数
     * @param callBack 回调
     * @param context 上下文
     * @param putJsonBody JSON参数
     */
    public void putRequest(NetCallBack callBack, Context context, String putJsonBody){
        RequestBody body = RequestBody.create(MediaType.parse("application/json;charset=utf-8"),putJsonBody);
        Log.e("TAG",ApiConfig.BASE_URL + requestUrl);
        Request request = new Request.Builder()
                .url(ApiConfig.BASE_URL + requestUrl)
                .addHeader("contentType","application/json;charset=UTF-8")
                .addHeader(Constant.POST_TOKEN,new SPUtils(context,Constant.SP_USER_FILE_NAME).getString(Constant.TOKEN))
                .put(body)
                .build();
        doCallBack(request,callBack);
    }

    /**
     * GET 方法 一般需要链接后跟参数 由config()静态方法传入一个map再进行拆分组装 拼接到地址后面
     * @param callBack 回调
     */
    public void getRequest(NetCallBack callBack){
        StringBuilder builder = new StringBuilder();
        if (params != null && params.size() > 0){
            builder.append("?");
            Iterator<String> keys = params.keySet().iterator();
            Iterator<Object> values = params.values().iterator();
            for (int i = 0 ; i < params.size() ; i++){
                builder.append(keys.next()+"="+values.next());
                if (i != params.size()-1)
                    builder.append("&");
            }
        }
        Request request = new Request.Builder()
                .url(ApiConfig.BASE_URL + requestUrl + builder)
                .build();
       doCallBack(request,callBack);
    }
    /**
     * GET 方法 一般需要链接后跟参数 单一参数
     * @param callBack 回调
     */
    public void getRequest(NetCallBack callBack,String param){
        Request request = new Request.Builder()
                .url(ApiConfig.BASE_URL + requestUrl + param)
                .build();
        doCallBack(request,callBack);
    }

     /**
      * @param context 上下文 用来获取sp存储的token
      * @param callBack 回调
      * @param param 参数
      *              考虑到get方法后面接的可能是多参或者单参，单参使用此方法的param参数，否则使用静态方法传入的params多参参数
      *
      *              注意，当此使用get请求不打算使用参数时，在使用此方法时的param参数请不要设置为null 否则会将‘null’拼接到地址后面
      *              我坑我自己
      */
     public void getRequest(Context context,NetCallBack callBack,String param){
         StringBuilder builder = new StringBuilder();
         Request request = null;
         //判断是否使用静态方法传入了参数，传入则拼接参数，未传入则直接跟在地址后面
         if (params != null && params.size() > 0){
             builder.append("?");
             Iterator<String> keys = params.keySet().iterator();
             Iterator<Object> values = params.values().iterator();
             for (int i = 0 ; i < params.size() ; i++){
                 builder.append(keys.next()+"="+values.next());
                 if (i != params.size()-1)
                     builder.append("&");
             }
             request = new Request.Builder()
                     .url(ApiConfig.BASE_URL + requestUrl + builder)
                     .addHeader(Constant.POST_TOKEN,SPUtils.config(context,Constant.SP_USER_FILE_NAME).getString(Constant.TOKEN))
                     .build();
         }else {
             if (param == null){
                 request = new Request.Builder()
                         .url(ApiConfig.BASE_URL + requestUrl)
                         .addHeader(Constant.POST_TOKEN,SPUtils.config(context,Constant.SP_USER_FILE_NAME).getString(Constant.TOKEN))
                         .build();
             }else {
                 request = new Request.Builder()
                         .url(ApiConfig.BASE_URL + requestUrl + param)
                         .addHeader(Constant.POST_TOKEN,SPUtils.config(context,Constant.SP_USER_FILE_NAME).getString(Constant.TOKEN))
                         .build();
             }
         }
         doCallBack(request,callBack);
     }

     /**
      * 无论 get post put 都走这里 这一步三者相同 方便检查token过期之类的
      * @param request 请求
      * @param callBack 回调
      */
    private void doCallBack(Request request,NetCallBack callBack){
        final Call call = client.newCall(request);
        call.enqueue(new Callback() {
            @Override
            public void onFailure(@NonNull Call call, @NonNull IOException e) {
                Looper.prepare();
                Toast.makeText(MApplication.getContext(),"加载超时，请刷新",Toast.LENGTH_SHORT).show();
                if (callBack!=null) callBack.onFailure(e);
                Looper.loop();
            }

            @Override
            public void onResponse(@NonNull Call call, @NonNull Response response) throws IOException {
                String res = response.body().string();
                Log.e("API",res);
                if (res.contains("认证失败")){
                    //TODO token失效 基本2天失效一次
                    Log.e("API",res);
                    Looper.prepare();
                    Toast.makeText(MApplication.getContext(),"登录过期，请重新登录",Toast.LENGTH_SHORT).show();
                    Intent intent = new Intent();
                    intent.setClass(MApplication.getContext(),LoginActivity.class);
                    intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                    //TODO     android.util.AndroidRuntimeException: Calling startActivity() from outside of an Activity  context requires the FLAG_ACTIVITY_NEW_TASK flag. Is this really what you want?
                    MApplication.getContext().startActivity(intent);
                    Looper.loop();
                }
                if (callBack!=null) callBack.onSuccess(res);
            }
        });
    }
}
